package com.ruoyi.activiti.service.impl;

import com.alibaba.fastjson.JSON;
import com.ruoyi.activiti.bpmnparse.BpmnParser;
import com.ruoyi.activiti.bpmnparse.x6translator.X6Helper;
import com.ruoyi.activiti.domain.*;
import com.ruoyi.activiti.mapper.*;
import com.ruoyi.activiti.service.ICustomProcessService;
import com.ruoyi.common.core.domain.entity.SysUser;
import com.ruoyi.common.utils.DateUtils;
import com.ruoyi.common.utils.SecurityUtils;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.system.mapper.SysUserMapper;
import lombok.extern.slf4j.Slf4j;
import org.activiti.engine.HistoryService;
import org.activiti.engine.RepositoryService;
import org.activiti.engine.RuntimeService;
import org.activiti.engine.TaskService;
import org.activiti.engine.history.HistoricActivityInstance;
import org.activiti.engine.history.HistoricActivityInstanceQuery;
import org.activiti.engine.history.HistoricProcessInstance;
import org.activiti.engine.history.HistoricTaskInstance;
import org.activiti.engine.repository.Deployment;
import org.activiti.engine.repository.ProcessDefinition;
import org.activiti.engine.runtime.ProcessInstance;
import org.activiti.engine.task.Comment;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.security.core.parameters.P;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import java.io.FileInputStream;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.concurrent.locks.AbstractQueuedSynchronizer;

@Slf4j
@Service
public class CustomProcessServiceImpl implements ICustomProcessService {
    @Autowired
    private RepositoryService repositoryService;
    @Autowired
    private HistoryService historyService;
    @Autowired
    private TaskService taskService;
    @Autowired
    private RuntimeService runtimeService;
    @Autowired
    private CustomProcessMapper customProcessMapper;
    @Autowired
    private CustomProcessMapperHis customProcessMapperHis;
    @Autowired
    private ProcessTaskMapper processTaskMapper;
    @Autowired
    private WlnProcessTaskMapper wlnProcessTaskMapper;
    @Autowired
    private ProcessCheckTaskMapper processCheckTaskMapper;
    @Value("${ruoyi.bpmnfile}")
    private String filePath;
    @Autowired
    private X6Helper x6Helper;
    @Autowired
    private SysUserMapper userMapper;
    @Autowired
    private CheckTaskMapper checkTaskMapper;

    /**
     * 接收流程中心推送过来的任务，有待办任务，已办，删除
     * @param params
     */
    @Override
    public void processTask(Map<String, Object> params) {
        String taskType = (String) params.get("taskType");
        // 待处理任务
        if("0".equals(taskType)) {
            saveTask(params);
        } else if("1".equals(taskType)) {
            // 已处理任务
            updateTask(params);
        } else if("2".equals(taskType)) {
            // 删除任务
            deleteTask(params);
        }
    }
    private void deleteTask(Map<String, Object> params){
        String taskId = (String) params.get("taskId");
        String instanceId = (String) params.get("instanceId");
        ProcessTask processTask = new ProcessTask();
        processTask.setTaskId(taskId);
        processTask.setInstanceId(instanceId);
        processTaskMapper.deleteTask(processTask);
    }
    private void updateTask(Map<String, Object> params){
        ProcessTask processTask = new ProcessTask();
        String assignee = (String) params.get("assignee");
        String taskType = (String) params.get("taskType");
        String taskId = (String) params.get("taskId");
        String opsUrl = (String) params.get("url");
        String instanceId = (String) params.get("instanceId");
        String createTime = (String) params.get("createTime");
        LocalDateTime localCreateTime = LocalDateTime.parse(createTime, DateTimeFormatter.ofPattern(DateUtils.YYYY_MM_DD_HH_MM_SS));
        processTask.setTaskCreateTime(localCreateTime);
        processTask.setAssignee(assignee);
        processTask.setTaskId(taskId);
        processTask.setTaskType(taskType);
        processTask.setInstanceId(instanceId);
        processTask.setUrl(opsUrl);
        processTaskMapper.updateTask(processTask);
    }
    private void saveTask(Map<String, Object> params){
        String taskType = (String) params.get("taskType");
//        String username = SecurityUtils.getUsername();
//        String nickName = SecurityUtils.getLoginUser().getUser().getNickName();
        ProcessTask processTask = new ProcessTask();
        processTask.setDel("0");
        String taskId = (String) params.get("taskId");
        processTask.setTaskId(taskId);
        String taskDefKey = (String) params.get("taskDefKey");
        processTask.setTaskKey(taskDefKey);
        String taskName = (String) params.get("taskName");
        processTask.setTaskName(taskName);
        processTask.setTaskType(taskType);
        processTask.setCreatedBy("process");
        String type = (String) params.get("type");
        processTask.setType(type);
        String instanceId = (String) params.get("instanceId");
        processTask.setInstanceId(instanceId);
        String name = (String) params.get("name");
        processTask.setTitle(name);
        String createTime = (String) params.get("createTime");
        LocalDateTime localCreateTime = LocalDateTime.parse(createTime, DateTimeFormatter.ofPattern(DateUtils.YYYY_MM_DD_HH_MM_SS));
        processTask.setTaskCreateTime(localCreateTime);
        String url = (String) params.get("url");
        processTask.setUrl(url);
        String procDefId = (String) params.get("procDefId");
        processTask.setProcDefKey(procDefId);
        String assignee = (String) params.get("assignee");
        processTask.setAssignee(assignee);
        processTaskMapper.insert(processTask);
    }
    @Transactional
    public void saveProcess(CustomProcess customProcess) {
        customProcess.setCreateBy(SecurityUtils.getUsername());
        customProcess.setCreateTime(LocalDateTime.now());
        customProcessMapper.saveProcess(customProcess);
    }

    @Override
    public List<CustomProcess> selectList(CustomProcess process) {
        return customProcessMapper.selectList(process);
    }

    @Override
    public CustomProcess selectById(Long id) {
        return customProcessMapper.selectById(id);
    }

    @Override
    public void deleteProcess(Long id) {
        customProcessMapper.deleteProcess(id);
    }

    @Transactional
    @Override
    public void updateProcess(CustomProcess customProcess) {
        // 更新流程
        customProcess.setUpdateBy(SecurityUtils.getUsername());
        customProcess.setUpdateTime(LocalDateTime.now());
        customProcessMapper.updateProcess(customProcess);
    }

    @Transactional
    @Override
    public void  deploy(Long id) {
        // 1. 获取流程对象
        CustomProcess process = selectById(id);
        String x6Json = process.getGraphData();
        // 2. 把流程图形数据转换成list map
        Map<String,Object> x6Map = (Map<String, Object>) JSON.parse(x6Json);
        List<Map<String,Object>> cellMap = (List<Map<String, Object>>) x6Map.get("cells");
        BpmnParser bpmnParser = new BpmnParser();
        bpmnParser.setProcessId(process.getProcessKey());
        bpmnParser.setProcessName(process.getProcessName());
        // 3. 初始化bpmn翻译器
        bpmnParser.initTranslator(cellMap);
        // 4. 解析x6 json成bpmn xml
        String name = filePath+process.getProcessName()+".bpmn20.xml";
        bpmnParser.parse(cellMap);
        try {
            // 5. 生成并保存xml文件
            bpmnParser.generateBpmnXml(name);
            // 6. 部署bpmn xml文件
            FileInputStream fis = new FileInputStream(name);
            Deployment deployment = repositoryService.createDeployment()
                    .name(process.getProcessName())
                    .addInputStream(process.getProcessName()+".bpmn20.xml", fis).deploy();
            // 7. 获取对应的流程实例
            ProcessDefinition processDefinition = repositoryService.createProcessDefinitionQuery()
                    .deploymentId(deployment.getId()).singleResult();
            // 8. 更新流程关联的流程定义id
            process.setProcDefId(processDefinition.getId());
            customProcessMapper.updateProcess(process);
            log.info("部署成功，部署ID=" + deployment.getId());
            // 保存到历史中
            customProcessMapperHis.saveProcess(process);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    @Override
    public List<ProcessHistory> listHistory(String procDefId) {
        List<ProcessHistory> processHistoryList = new ArrayList<>();
        List<HistoricActivityInstance> activities =
                historyService.createHistoricActivityInstanceQuery()
                        .processDefinitionId(procDefId)
                        .orderByHistoricActivityInstanceEndTime().asc()
                        .list();
        for (HistoricActivityInstance instance : activities) {
            ProcessHistory processHistory = new ProcessHistory();
            processHistory.setActId(instance.getActivityId());
            if(instance.getEndTime() == null) {
                processHistory.setStatus("running");
            } else {
                processHistory.setStatus("success");
            }
            processHistory.setAssigneeName(instance.getAssignee());
            // 设置节点意见信息
            String taskId = instance.getTaskId();
            List<Comment> comment = taskService.getTaskComments(taskId, "comment");
            if (!CollectionUtils.isEmpty(comment)) {
                processHistory.setComment(comment.get(0).getFullMessage());
            }
            // 如果是撤销（deleteReason 不为 null），写入审批意见栏
            if (StringUtils.isNotBlank(instance.getDeleteReason())) {
                processHistory.setComment(instance.getDeleteReason());
            }
            processHistoryList.add(processHistory);
        }
        return processHistoryList;
    }
    private void copyDefaultProp(HistoricActivityInstance instance,HistoryTask historyTask){
        historyTask.setTaskName(instance.getActivityName());
        historyTask.setTaskDefId(instance.getActivityId());
        historyTask.setTaskId(instance.getTaskId());
        historyTask.setInstanceId(instance.getProcessInstanceId());
        historyTask.setProcDefId(instance.getProcessDefinitionId());
        historyTask.setTaskCreateTime(instance.getStartTime());
    }
    @Override
    public List<HistoryTask> listTaskHistory(String instanceId) {
        // 说明：以下实现方案是手动封装 开始节点 和 结束节点 的数据，因此不考虑分页功能
        List<HistoryTask> activityList = new ArrayList<>();
        HistoricActivityInstanceQuery query = historyService.createHistoricActivityInstanceQuery();
        List<HistoricActivityInstance> list = query.processInstanceId(instanceId)
                .activityType("userTask")
                .orderByHistoricActivityInstanceEndTime()
                .asc()
                .list();
        list.forEach(instance -> {
            HistoryTask historyTask = new HistoryTask();
            historyTask.setAssignee(instance.getAssignee());
            copyDefaultProp(instance,historyTask);
            if(instance.getEndTime() == null) {
                historyTask.setTaskStatus("running");
                historyTask.setType("primary");
            } else {
                historyTask.setTaskStatus("success");
                historyTask.setType("success");
            }
            String taskId = instance.getTaskId();
            List<Comment> comment = taskService.getTaskComments(taskId, "comment");
            if (!CollectionUtils.isEmpty(comment)) {
                historyTask.setComment(comment.get(0).getFullMessage());
            }
            // 如果是撤销（deleteReason 不为 null），写入审批意见栏
            if (StringUtils.isNotBlank(instance.getDeleteReason())) {
                historyTask.setComment(instance.getDeleteReason());
            }
            SysUser sysUser = userMapper.selectUserByUserName(instance.getAssignee());
            // 查询审批记录
            CheckTask checkTaskParam = new CheckTask();
            checkTaskParam.setTaskId(taskId);
            checkTaskParam.setInstanceId(instance.getProcessInstanceId());
            CheckTask checkTask = processCheckTaskMapper.queryByInstanceId(checkTaskParam);
            // 获取任务关联的链接url
            WlnProcessTask processTask = new WlnProcessTask();
            processTask.setInstanceId(instance.getProcessInstanceId());
            processTask.setTaskId(taskId);
            List<WlnProcessTask> taskList = wlnProcessTaskMapper.getTaskByInstanceId(processTask);
            if(taskList.size() > 0) {
                String url = taskList.get(0).getUrl();
                historyTask.setUrl(url);
            }
            // 如果查询不到审批记录，证明该任务没有进行审批而被删除的，所以要过滤掉。
            if(checkTask != null) {
                historyTask.setPass(checkTask.getReviewStatus());
                if (sysUser != null) {
                    historyTask.setAssignee(sysUser.getNickName());
                }
                activityList.add(historyTask);
            }
        });

        // 以下手动封装发起人节点的数据
        HistoryTask startActivity = new HistoryTask();
        query = historyService.createHistoricActivityInstanceQuery();
        HistoricActivityInstance startActivityInstance = query.processInstanceId(instanceId)
                .activityType("startEvent")
                .singleResult();
        copyDefaultProp(startActivityInstance,startActivity);
        HistoricProcessInstance historicProcessInstance = historyService.createHistoricProcessInstanceQuery()
                .processInstanceId(instanceId)
                .singleResult();
        startActivity.setAssignee(historicProcessInstance.getStartUserId());
        startActivity.setTaskStatus("success");
        startActivity.setType("success");
        SysUser sysUser = userMapper.selectUserByUserName(historicProcessInstance.getStartUserId());
        if (sysUser != null) {
            startActivity.setAssignee(sysUser.getNickName());
        }
        startActivity.setComment("提交申请");

        // 手动过滤该条发起人数据
        boolean necessaryAdd = true;
        if (necessaryAdd) {
            activityList.add(0, startActivity);
        }

        // 以下手动封装结束节点的数据
        HistoryTask endActivity = new HistoryTask();
        query = historyService.createHistoricActivityInstanceQuery();
        HistoricActivityInstance endActivityInstance = query.processInstanceId(instanceId)
                .activityType("endEvent")
                .singleResult();
        if (null != endActivityInstance) {
            copyDefaultProp(endActivityInstance, endActivity);
            endActivity.setAssignee("admin");
            sysUser = userMapper.selectUserByUserName("admin");
            if (sysUser != null) {
                endActivity.setAssignee(sysUser.getNickName());
            }
            startActivity.setTaskStatus("success");
            startActivity.setType("success");
            endActivity.setComment("自动结束");
            activityList.add(endActivity);
        }
        return activityList;
    }

    @Override
    public List<ProcessHistory> listHistoryForInstanceId(String InstanceId) {
        List<ProcessHistory> processHistoryList = new ArrayList<>();
        List<HistoricActivityInstance> activities =
                historyService.createHistoricActivityInstanceQuery()
                        .processInstanceId(InstanceId)
                        .orderByHistoricActivityInstanceEndTime().asc()
                        .list();
        for (HistoricActivityInstance instance : activities) {
            ProcessHistory processHistory = new ProcessHistory();
            processHistory.setActId(instance.getActivityId());
            if(instance.getEndTime() == null) {
                processHistory.setStatus("running");
            } else {
                processHistory.setStatus("success");
            }
            processHistory.setAssigneeName(instance.getAssignee());
            // 设置节点意见信息
            String taskId = instance.getTaskId();
            List<Comment> comment = taskService.getTaskComments(taskId, "comment");
            if (!CollectionUtils.isEmpty(comment)) {
                processHistory.setComment(comment.get(0).getFullMessage());
            }
            // 如果是撤销（deleteReason 不为 null），写入审批意见栏
            if (StringUtils.isNotBlank(instance.getDeleteReason())) {
                processHistory.setComment(instance.getDeleteReason());
            }
            processHistoryList.add(processHistory);
        }
        return processHistoryList;
    }
    public String getGraphDataForInstance(String instanceId){
//        List<ProcessInstance> processInstanceList = runtimeService
//                .createProcessInstanceQuery()
//                .processInstanceId(instanceId)
//                .list();
        List<HistoricProcessInstance> processInstanceList = historyService.createHistoricProcessInstanceQuery()
                .processInstanceId(instanceId)
                .list();
        HistoricProcessInstance processInstance = null;
        if(processInstanceList.size() > 0) {
            processInstance = processInstanceList.get(0);
        }
        if(processInstance != null) {
            CustomProcess customProcess = customProcessMapperHis.selectByProcDefId(processInstance.getProcessDefinitionId());
            return customProcess.getGraphData();
        } else {
            return "";
        }
    }
}
